# -*- coding: utf-8 -*-
"""Controlador de Alfabetos"""
from formencode import validators
from lex import model
from lex.lib.base import BaseController
from lex.model import metadata, DBSession
from lex.model.model import Alfabeto
from lex.widgets import alfabetos_form
from lex.widgets.alfabetos_form import crear_alfabeto_form, editar_alfabeto_form
from pylons.i18n import ugettext as _, lazy_ugettext as l_
from sqlalchemy import func
from sqlalchemy.exc import IntegrityError, SQLAlchemyError
from tg import expose, flash, require, url, request, redirect, tmpl_context, \
    validate
import transaction
from webhelpers import paginate

from repoze.what import predicates
from tgext.admin.controller import AdminController, AdminConfig
from tgext.admin.tgadminconfig import TGAdminConfig


__all__ = ['AlfabetosController']

class AlfabetosController(BaseController):
    @expose('lex.templates.alfabetos.listado')    
    def listado(self, **kw):
        return dict()
        
    
    @validate(validators={"page":validators.Int(), "rp":validators.Int()})
    @expose('json')
    def datos(self, page='1', rp='25', sortname='nombre', sortorder='asc', qtype=None, query=None):
	  try:
		
		alfabetos = DBSession.query(Alfabeto).order_by(Alfabeto.id_alfabeto)
		
		total = alfabetos.count()
            	#column = getattr(Alfabetos, sortname)
		print "foooooooooooooooo000000000000000000000000000"
		rows = [{'id'  : alfabeto.id_alfabeto,
                        'cell': [alfabeto.id_alfabeto,
			    alfabeto.nombre_alfabeto,
                            alfabeto.definicion_alfabeto]} for alfabeto in alfabetos]
                result = dict(page=page, total=total, rows=rows)
          except:
                result = dict() 
          return result


    @expose('lex.templates.alfabetos.nuevo_alfabeto')
    def nuevo(self, **kw):
        """Despliega el formulario para añadir un nuevo Alfabeto."""
        try:
            #Establecemos el contexto de nuestro formulario de creacion de alfabeto.
            tmpl_context.form = crear_alfabeto_form
        except SQLAlchemyError:
            flash(_("No se pudo acceder a Creacion de Alfabetos! SQLAlchemyError..."), 'error')
            redirect("/alfabetos/listado")
        except (AttributeError, NameError):
            flash(_("No se pudo acceder a Creacion de Alfabeto! Hay Problemas con el servidor..."), 'error')
            redirect("/alfabetos/listado")

        return dict(nombre_modelo='Alfabeto', value=kw)

    @validate(crear_alfabeto_form, error_handler=nuevo)
    @expose()
    def add(self, **kw):
        """Metodo para agregar un registro a la base de datos """
        try:
################################################################################
#Advertencia: Estas validaciones tambien se realizan en la funcion "update". Asi
#que, cualquier cambio realizado aqui, tambien debe considerarse si se realiza o
#no en la funcion "update".
######################### VALIDACION DEL NOMBRE ################################
            #Realizamos algunas comprobaciones del nombre del alfabeto.
            nombre_alfabeto = kw['nombre_alfabeto']
            lista_nombre = nombre_alfabeto.split()
            nombre_alfabeto = " ".join(lista_nombre) #Nombre final del alfabeto.

######################### VALIDACION DE LA DEFINICION ##########################

            #Verificamos la correcta definicion del alfabeto. El alfabeto solo puede
            #constar de simbolos individuales separados entre espacios en blanco.
            #Extraemos todas las subcadenas tomando como delimitador el 
            #espacio en blanco. De cada subcadena solo consideramos el primer caracter,
            #en caso que se hayan introducidos varios.Tambien verificamos que no se hayan 
            #introducido operadores de expresiones regulares como simbolos.
            definicion_alfabeto = kw['definicion_alfabeto']
            lista_definicion = []
            lista_definicion = definicion_alfabeto.split()
            lista_limpia = []

            for subcadena in lista_definicion:
                for sub in subcadena:
                    if sub[0]=="+" or sub[0]=="*" or sub[0]=="?" or sub[0]=="|" or sub[0]=="." or sub[0]=="(" or sub[0]==")":
                       break
                    else:
                       lista_limpia.append(sub)
                       break

            #Eliminamos los duplicados y ordenamos la lista, luego 
            #convertimos la lista en una cadena.
            lista_limpia = list(set(lista_limpia))
            lista_limpia.sort()
            definicion_alfabeto = " ".join(lista_limpia) #Definicion final del alfabeto.

################################################################################

            #Creamos un nuevo alfabeto e insertamos en la BD.
            alfabeto = Alfabeto()
            alfabeto.nombre_alfabeto = nombre_alfabeto
            alfabeto.definicion_alfabeto = definicion_alfabeto
            DBSession.add(alfabeto)

            #Confirmamos la transaccion.
            DBSession.flush()
            transaction.commit()
        except IntegrityError:
            transaction.abort()
            flash(_("No se ha guardado! Hay Problemas con el servidor..."), 'error')
            redirect("/alfabetos/listado")
        except SQLAlchemyError:
            flash(_("No se ha guardado! SQLAlchemyError..."), 'error')
            redirect("/alfabetos/listado")
        except (AttributeError, NameError):
            flash(_("No se ha guardado! Hay Problemas con el servidor..."), 'error')
            redirect("/alfabetos/listado")
        else:
            flash(_("Alfabeto creado!"), 'ok')
    
        redirect("/alfabetos/listado")

    @expose('lex.templates.alfabetos.editar_alfabeto')
    def editar(self, id_alfabeto, **kw):
        """Metodo que rellena el formulario para editar los datos de un Alfabeto"""
        try:
            #Establecemos el contexto del formulario de edicion de alfabetos.
            tmpl_context.form = editar_alfabeto_form

            #Cargamos el formulario con los datos del alfabeto a editar.
            alfabeto = DBSession.query(Alfabeto).get(id_alfabeto)
            kw['id_alfabeto'] = alfabeto.id_alfabeto
            kw['nombre_alfabeto'] = alfabeto.nombre_alfabeto
            kw['definicion_alfabeto'] = alfabeto.definicion_alfabeto
        except SQLAlchemyError:
            flash(_("No se pudo acceder a Edicion de Alfabetos! SQLAlchemyError..."), 'error')
            redirect("/alfabetos/listado")
        except (AttributeError, NameError):
            flash(_("No se pudo acceder a Edicion de Alfabetos! Hay Problemas con el servidor..."), 'error')
            redirect("/alfabetos/listado")

        return dict(value=alfabeto)

    @validate(editar_alfabeto_form, error_handler=editar)
    @expose()
    def update(self, **kw):        
        """Metodo que actualizar la base de datos"""
        try:
################################################################################
#Advertencia: Estas validaciones tambien se realizan en la funcion "add". Asi
#que, cualquier cambio realizado aqui, tambien debe considerarse si se realiza o
#no en la funcion "add".
######################### VALIDACION DEL NOMBRE ################################
            #Realizamos algunas comprobaciones del nombre del alfabeto.
            nombre_alfabeto = kw['nombre_alfabeto']
            lista_nombre = nombre_alfabeto.split()
            nombre_alfabeto = " ".join(lista_nombre) #Nombre final del alfabeto.

######################### VALIDACION DE LA DEFINICION ##########################
            
            #Verificamos la correcta definicion del alfabeto. El alfabeto solo puede
            #constar de simbolos individuales separados entre espacios en blanco.
            #Extraemos todas las subcadenas tomando como delimitador el 
            #espacio en blanco. De cada subcadena solo consideramos el primer caracter,
            #en caso que se hayan introducidos varios.Tambien verificamos que no se hayan 
            #introducido operadores de expresiones regulares como simbolos.
            definicion_alfabeto = kw['definicion_alfabeto']
            lista_definicion = []
            lista_definicion = definicion_alfabeto.split()
            lista_limpia = []

            for subcadena in lista_definicion:
                for sub in subcadena:
                    if sub[0]=="+" or sub[0]=="*" or sub[0]=="?" or sub[0]=="|" or sub[0]=="." or sub[0]=="(" or sub[0]==")":
                       break
                    else:
                       lista_limpia.append(sub)
                       break

            #Eliminamos los duplicados y ordenamos la lista, luego 
            #convertimos la lista en una cadena.
            lista_limpia = list(set(lista_limpia))
            lista_limpia.sort()
            definicion_alfabeto = " ".join(lista_limpia) #Definicion final del alfabeto.

################################################################################

            #Guardamos los cambios realizados en la edicion del alfabeto.
            id_alfabeto = kw['id_alfabeto']
            alfabeto = DBSession.query(Alfabeto).get(id_alfabeto)
            alfabeto.nombre_alfabeto = nombre_alfabeto
            alfabeto.definicion_alfabeto = definicion_alfabeto

            #Confirmamos la transaccion
            DBSession.flush()
            transaction.commit()

################################################################################
#Advertencia: Las siguientes verificaciones tambien se realizan en la funcion 
#"delete". Asi que, cualquier cambio realizado aqui, tambien debe considerarse 
#si se realiza o no en la funcion "delete".
############### VERIFICACION DE LOS ANALIZADORES AFECTADOS #####################

            #Por cada analizador afectado, establecemos a "False" el campo 
            #"validado" de sus expresiones regulares. Tambien establecemos a
            #"False" el campo "estado" de los analizadores afectados.
            alfabeto_editado = DBSession.query(Alfabeto).get(id_alfabeto)
            analizadores_afectados = alfabeto_editado.analizadores_lexicos
            if analizadores_afectados != []:
               for analizador_afectado in analizadores_afectados:
                   expresiones_afectadas = analizador_afectado.expresiones_regulares
                   if expresiones_afectadas != []:
                      for expresion_afectada in expresiones_afectadas:
                          expresion_afectada.validado = False
                   analizador_afectado.estado = False


################################################################################
        except IntegrityError:
            transaction.abort()
            flash(_("No se han guardado los cambios! Hay Problemas con el servidor..."), 'error')
            redirect("/alfabetos/listado")
        except SQLAlchemyError:
            flash(_("No se han guardado los cambios! SQLAlchemyError..."), 'error')
            redirect("/alfabetos/listado")
        except (AttributeError, NameError):
            flash(_("No se han guardado los cambios! Hay Problemas con el servidor..."), 'error')
            redirect("/alfabetos/listado")
        else:
            flash(_("Se han guardado los cambios!"), 'ok')

        redirect("/alfabetos/listado")

    @expose('lex.templates.alfabetos.confirmar_eliminar_alfabeto')
    def confirmar_eliminar_alfabeto(self, id_alfabeto, **kw):
        """Despliega confirmacion de eliminacion"""
        try:
            #Se muestran los datos del alfabeto seleccionado.
            alfabeto = DBSession.query(Alfabeto).get(id_alfabeto)
        except SQLAlchemyError:
            flash(_("No se pudo acceder a Eliminacion de Alfabetos! SQLAlchemyError..."), 'error')
            redirect("/alfabetos/listado")
        except (AttributeError, NameError):
            flash(_("No se pudo acceder a Eliminacion de Alfabetos! Hay Problemas con el servidor..."), 'error')
            redirect("/alfabetos/listado")

        return dict(value=alfabeto)

    @validate(validators={"page":validators.Int(), "rp":validators.Int()})
    @expose('json')
    def delete(self, id_alfabeto, **kw):
        """Metodo que elimina un registro de la base de datos"""
        try:
################################################################################
#Advertencia: Las siguientes verificaciones tambien se realizan en la funcion 
#"update". Asi que, cualquier cambio realizado aqui, tambien debe considerarse 
#si se realiza o no en la funcion "update".
############### VERIFICACION DE LOS ANALIZADORES AFECTADOS #####################

            #Por cada analizador afectado, establecemos a "False" el campo 
            #"validado" de sus expresiones regulares. Tambien establecemos a
            #"False" el campo "estado" de los analizadores afectados.
            alfabeto_a_eliminar = DBSession.query(Alfabeto).get(id_alfabeto)
	    nombre=alfabeto_a_eliminar.nombre_alfabeto
            analizadores_afectados = alfabeto_a_eliminar.analizadores_lexicos
            if analizadores_afectados != []:
               for analizador_afectado in analizadores_afectados:
                   expresiones_afectadas = analizador_afectado.expresiones_regulares
                   if expresiones_afectadas != []:
                      for expresion_afectada in expresiones_afectadas:
                          expresion_afectada.validado = False
                   analizador_afectado.estado = False


################################################################################

            #Eliminamos el alfabeto de la base de datos.
            DBSession.delete(DBSession.query(Alfabeto).get(id_alfabeto))

            #Confirmamos la transaccion.
            DBSession.flush()
            transaction.commit()
        except IntegrityError:
            transaction.abort()
            msg="No se ha eliminado! Hay Problemas con el servidor..."
	    type="error"
            redirect("/alfabetos/listado")
        except SQLAlchemyError:
            msg="No se ha eliminado! SQLAlchemyError..."
	    type="error"
            redirect("/alfabetos/listado")
        except (AttributeError, NameError):
            msg="No se ha eliminado! Hay Problemas con el servidor..."
	    type="error"
            redirect("/alfabetos/listado")
        else:
            msg="El alfabeto se ha eliminado con exito!."
	    type="succes"

        return dict(msg=msg,nombre=nombre,type=type)
